<?php

!defined('ACLOUD_PATH') && exit('Forbidden');

class ACloudSysDataFlowServiceCrawler
{
    private $perpage = 100;

    public function crawlTable($tableName, $page, $perpage)
    {
        list($tableName, $page, $perpage) = array(trim($tableName), intval($page), intval($perpage));
        $page < 1 && $page = 1;
        $this->setPerpage($perpage);
        if (!$tableName) {
            return '';
        }
        $tableSettingService = ACloudSysCoreCommon::loadSystemClass('table.settings', 'config.service');
        $tableSetting = $tableSettingService->getSettingByTableNameWithReplace($tableName);
        if (!ACloudSysCoreS::isArray($tableSetting)) {
            return '';
        }
        if (!$tableSetting['status']) {
            return '';
        }
        list($total, $data) = $tableSetting['primary_key'] ? $this->getTableDataByPrimaryKey($tableSetting, $tableName, $page) : $this->getTableDataWithoutPrimaryKey($tableSetting, $tableName, $page);
        if ($total < 1) {
            return '';
        }
        $totalPages = ceil($total / $this->perpage);

        return $this->outputDataFlow($data, $totalPages);
    }

    public function crawlTableMaxId($tableName)
    {
        $tableName = trim($tableName);
        if (!$tableName) {
            return '';
        }
        $tableSettingService = ACloudSysCoreCommon::loadSystemClass('table.settings', 'config.service');
        $tableSetting = $tableSettingService->getSettingByTableNameWithReplace($tableName);
        if (!ACloudSysCoreS::isArray($tableSetting)) {
            return '';
        }
        if (!$tableSetting['status']) {
            return '';
        }
        $maxId = $this->getMaxPrimaryKeyId($tableSetting);

        return $this->outputDataFlow(array(array('maxid' => $maxId)));
    }

    public function crawlTableByIdRange($startId, $endId, $tableName)
    {
        list($tableName, $startId, $endId) = array(trim($tableName), intval($startId), intval($endId));
        if (!$tableName) {
            return '';
        }
        if ($startId < 0 || $startId > $endId || $endId < 1) {
            return '';
        }
        $tableSettingService = ACloudSysCoreCommon::loadSystemClass('table.settings', 'config.service');
        $tableSetting = $tableSettingService->getSettingByTableNameWithReplace($tableName);
        if (!ACloudSysCoreS::isArray($tableSetting)) {
            return '';
        }
        if (!$tableSetting['status']) {
            return '';
        }
        if (!$tableSetting['primary_key']) {
            return '';
        }
        $data = $this->getDataByPrimaryKeyRange($tableSetting, $startId, $endId);

        return $this->outputDataFlow($data);
    }

    public function crawlDelta()
    {
    }

    public function crawlSqlLog($startTime, $endTime, $page, $perpage)
    {
        list($startTime, $endTime, $page, $perpage) = array(intval($startTime), intval($endTime), intval($page), intval($perpage));
        if ($startTime > $endTime) {
            return '';
        }
        $page < 1 && $page = 1;
        $perpage < 1 && $perpage = $this->perpage;
        $sqlLogService = ACloudSysCoreCommon::loadSystemClass('sql.log', 'config.service');
        $result = $sqlLogService->getSqlLogsByTimestamp($startTime, $endTime, $page, $perpage);
        if (!ACloudSysCoreS::isArray($result)) {
            return '';
        }

        return $this->outputDataFlow($result);
    }

    public function crawlSqlLogCount($startTime, $endTime)
    {
        list($startTime, $endTime) = array(intval($startTime), intval($endTime));
        if ($startTime > $endTime) {
            return '';
        }
        $sqlLogService = ACloudSysCoreCommon::loadSystemClass('sql.log', 'config.service');
        $result = $sqlLogService->countSqlLogsByTimestamp($startTime, $endTime);

        return $this->outputDataFlow(array(array('count' => intval($result))));
    }

    public function deleteSqlLog($startTime, $endTime)
    {
        list($startTime, $endTime) = array(intval($startTime), intval($endTime));
        $sqlLogService = ACloudSysCoreCommon::loadSystemClass('sql.log', 'config.service');
        $result = $sqlLogService->deleteSqlLogByTimestamp($startTime, $endTime);

        return $this->outputDataFlow(array(array('delete' => intval($result))));
    }

    public function crawlDeletedId($type, $startId, $endId)
    {
        list($type, $startId, $endId) = array(trim(strtolower($type)), intval($startId), intval($endId));
        if (!$type) {
            return '';
        }
        if ($startId < 0 || $startId > $endId || $endId < 1) {
            return '';
        }
        list($commonFactory, $method) = array($this->getVerCommonFactory(), 'getVersionCommon'.ucfirst($type));
        if (!method_exists($commonFactory, $method)) {
            return '';
        }
        $service = $commonFactory->$method();
        if (!$service || !is_object($service) || !method_exists($service, 'getDeletedId')) {
            return '';
        }
        $result = $service->getDeletedId($startId, $endId);

        return $this->outputDataFlow($result);
    }

    public function crawlThreadRange($startId, $endId)
    {
        list($startId, $endId) = array(intval($startId), intval($endId));
        $commonFactory = $this->getVerCommonFactory();
        $commonThread = $commonFactory->getVersionCommonThread();
        $result = $commonThread->getThreadsByRange($startId, $endId);

        return $this->outputDataFlow($result);
    }

    public function crawlMemberRange($startId, $endId)
    {
        list($startId, $endId) = array(intval($startId), intval($endId));
        $commonFactory = $this->getVerCommonFactory();
        $commonUser = $commonFactory->getVersionCommonUser();
        $result = $commonUser->getUsersByRange($startId, $endId);

        return $this->outputDataFlow($result);
    }

    public function crawlPostRange($startId, $endId)
    {
        list($startId, $endId) = array(intval($startId), intval($endId));
        $commonFactory = $this->getVerCommonFactory();
        $commonPost = $commonFactory->getVersionCommonPost();
        $result = $commonPost->getPostsByRange($startId, $endId);

        return $this->outputDataFlow($result);
    }

    public function crawlPostMaxId()
    {
        $commonFactory = $this->getVerCommonFactory();
        $commonPost = $commonFactory->getVersionCommonPost();
        $maxId = $commonPost->getPostMaxId();

        return $this->outputDataFlow(array(array('maxid' => $maxId)));
    }

    public function crawlAttachRange($startId, $endId)
    {
        list($startId, $endId) = array(intval($startId), intval($endId));
        $commonFactory = $this->getVerCommonFactory();
        $commonAttach = $commonFactory->getVersionCommonAttach();
        $result = $commonAttach->getAttachsByRange($startId, $endId);

        return $this->outputDataFlow($result);
    }

    public function crawlForumRange($startId, $endId)
    {
        list($startId, $endId) = array(intval($startId), intval($endId));
        $commonFactory = $this->getVerCommonFactory();
        $commonForum = $commonFactory->getVersionCommonForum();
        $result = $commonForum->getForumsByRange($startId, $endId);

        return $this->outputDataFlow($result);
    }

    public function crawlDiaryRange($startId, $endId)
    {
        list($startId, $endId) = array(intval($startId), intval($endId));
        $commonFactory = $this->getVerCommonFactory();
        $commonDiary = $commonFactory->getVersionCommonDiary();
        $result = $commonDiary->getDiarysByRange($startId, $endId);

        return $this->outputDataFlow($result);
    }

    public function crawlColonyRange($startId, $endId)
    {
        list($startId, $endId) = array(intval($startId), intval($endId));
        $commonFactory = $this->getVerCommonFactory();
        $commonColony = $commonFactory->getVersionCommonColony();
        $result = $commonColony->getColonysByRange($startId, $endId);

        return $this->outputDataFlow($result);
    }

    public function crawlThreadDelta($startTime, $endTime, $page, $perpage)
    {
        list($startTime, $endTime, $page, $perpage) = array(intval($startTime), intval($endTime), intval($page), intval($perpage));
        $page < 1 && $page = 1;
        $perpage < 1 && $perpage = $this->perpage;
        $commonFactory = $this->getVerCommonFactory();
        $commonThread = $commonFactory->getVersionCommonThread();
        $result = $commonThread->getThreadsByModifiedTime($startTime, $endTime, $page, $perpage);

        return $this->outputDataFlow($result);
    }

    public function crawlThreadDeltaCount($startTime, $endTime)
    {
        list($startTime, $endTime) = array(intval($startTime), intval($endTime));
        $commonFactory = $this->getVerCommonFactory();
        $commonThread = $commonFactory->getVersionCommonThread();
        $result = $commonThread->getThreadDeltaCount($startTime, $endTime);

        return $this->outputDataFlow(array(array('count' => $result)));
    }

    public function getAttachDirectoriesForStorage()
    {
        $commonFactory = $this->getVerCommonFactory();
        $commonAttach = $commonFactory->getVersionCommonAttach();
        $result = $commonAttach->getAttachDirectories();

        return $this->outputDataFlow($result);
    }

    public function getAttachesForStorage($dir)
    {
        $commonFactory = $this->getVerCommonFactory();
        $commonAttach = $commonFactory->getVersionCommonAttach();
        $result = $commonAttach->getAttachesForStorage($dir);

        return $this->outputDataFlow($result);
    }

    private function getTableDataByPrimaryKey($tableSetting, $tableName, $page)
    {
        list($start, $end) = $this->getIdRange($page);
        $generalDataService = ACloudSysCoreCommon::loadSystemClass('generaldata', 'config.service');
        $maxId = $this->getMaxPrimaryKeyId($tableSetting);
        if ($maxId < 1) {
            return array(0, array());
        }
        $data = $this->getDataByPrimaryKeyRange($tableSetting, $start, $end);

        return array($maxId, $data);
    }

    private function getTableDataWithoutPrimaryKey($tableSetting, $tableName, $page)
    {
        list($offset, $limit) = $this->getPageRange($page);
        $generalDataService = ACloudSysCoreCommon::loadSystemClass('generaldata', 'config.service');
        $countSql = sprintf('SELECT COUNT(*) as count FROM %s', ACloudSysCoreS::sqlMetadata($tableSetting['name']));
        list($count) = $generalDataService->executeSql($countSql);
        $count = $count['count'];
        if ($count < 1) {
            return array(0, array());
        }
        $dataSql = sprintf('SELECT * FROM %s %s', ACloudSysCoreS::sqlMetadata($tableSetting['name']), ACloudSysCoreS::sqlLimit($offset, $limit));
        $data = $generalDataService->executeSql($dataSql);

        return array($count, $data);
    }

    private function outputDataFlow($data, $totalPages = null)
    {
        $charset = ACloudSysCoreCommon::getGlobal('g_charset');
        $formatService = ACloudSysCoreCommon::loadSystemClass('format');

        return $formatService->dataFlowXmlFormat($data, $charset, $totalPages);
    }

    private function getMaxPrimaryKeyId($tableSetting)
    {
        $generalDataService = ACloudSysCoreCommon::loadSystemClass('generaldata', 'config.service');
        $countSql = sprintf('SELECT MAX(%s) as count FROM %s', ACloudSysCoreS::sqlMetadata($tableSetting['primary_key']), ACloudSysCoreS::sqlMetadata($tableSetting['name']));
        list($result) = $generalDataService->executeSql($countSql);

        return $result['count'];
    }

    private function getDataByPrimaryKeyRange($tableSetting, $start, $end)
    {
        $generalDataService = ACloudSysCoreCommon::loadSystemClass('generaldata', 'config.service');
        $dataSql = sprintf('SELECT * FROM %s WHERE %s >= %s AND %s <= %s', ACloudSysCoreS::sqlMetadata($tableSetting['name']), ACloudSysCoreS::sqlMetadata($tableSetting['primary_key']), ACloudSysCoreS::sqlEscape($start), ACloudSysCoreS::sqlMetadata($tableSetting['primary_key']), ACloudSysCoreS::sqlEscape($end));

        return $generalDataService->executeSql($dataSql);
    }

    private function getIdRange($page)
    {
        $page = intval($page) > 0 ? intval($page) : 1;
        $start = ($page - 1) * $this->perpage + 1;
        $end = $start + $this->perpage - 1;

        return array($start, $end);
    }

    private function getPageRange($page)
    {
        $page = intval($page) > 0 ? intval($page) : 1;
        $start = ($page - 1) * $this->perpage;
        $start = intval($start);

        return array($start, $this->perpage, $page);
    }

    public function setPerpage($perpage)
    {
        $perpage = intval($perpage);
        if ($perpage < 1) {
            return false;
        }
        $this->perpage = $perpage;

        return true;
    }

    private function getVerCommonFactory()
    {
        require_once Wind::getRealPath('ACLOUD_VER:common.ACloudVerCommonFactory');

        return ACloudVerCommonFactory::getInstance();
    }
}
